package com.chang.cart.interceptor;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.chang.cart.vo.UserInfoTo;
import com.chang.common.constant.AuthServerConstant;
import com.chang.common.constant.CartConstant;
import com.chang.common.vo.MemberResponseVo;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.util.UUID;

/**
 * @author: changzhenxi
 * @date: 2024年12月16日 15:45
 * @Version: 1.0
 * @description: 执行目标方法之前判断用户的登陆状态 并封装
 */
@Slf4j
@Component
public class CartInterceptor implements HandlerInterceptor {

    public static ThreadLocal<UserInfoTo> memberThreadLocal = new ThreadLocal<>();

    // 目标方法执行之前及逆行拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        UserInfoTo userInfo = new UserInfoTo();
        HttpSession session = request.getSession();
        Object attribute = session.getAttribute(AuthServerConstant.LOGIN_USER);
        // 注意这里不能直接强转 LinkedHashMap这个坑,有一些返回的map格式的数据,当你在根据key获取 value
        // 并将他转化为自己封装的实体类的时候总是报这个错误 LinkedHashMap cannot be cast to xxx 类型转换异常
        //  MemberResponseVo attribute = (MemberResponseVo) session.getAttribute(AuthServerConstant.LOGIN_USER);
        // 这里我输出之后发现可以转为json字符串 然后我干脆直接属性拷贝了
        MemberResponseVo memberResponseVo = new MemberResponseVo();
        BeanUtil.copyProperties(attribute, memberResponseVo);


        if (memberResponseVo.getId() != null) {
            // 用户已经登陆了
            log.info("session中用户信息拷贝完毕=>memberResponseVo->{}", memberResponseVo);
            userInfo.setUserId(memberResponseVo.getId());
        }
        // TODO 我懂了!!! 这里我在纳闷为什么即使登陆了还要再分配一个临时用户专用的userKey,
        //  因为如果先使用临时登录添加购物车,然后再登录账号使用购物车就需要吧登录之前临时用户的购物车内容也添加进来 所以to对象既要保存userId也需要保存userKey
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                String name = cookie.getName();
                if (StrUtil.equals(name, CartConstant.TEMP_USER_COOKIE_NAME)) {
                    userInfo.setUserKey(cookie.getValue());
                    break;
                }
            }
        }
        // 如果没有用户登录，则必分配一个临时用户，方便后续业务逻辑
        if (userInfo.getUserId() == null && StrUtil.isBlank(userInfo.getUserKey())) {
            String randomId = UUID.randomUUID().toString();
            userInfo.setUserKey(randomId);
            userInfo.setTempUser(true);
        }
        // 单次请求从过滤器->拦截器->controller->service都是同一个线程 可以将数据存放到ThreadLocal中,方便不同方法提取,省去直接传递对象的麻烦 并且线程结束就自动销毁
        memberThreadLocal.set(userInfo);
        return true;
    }

    // 业务执行之后 重复延长临时用户的cookie过期时间
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

        UserInfoTo userInfoTo = memberThreadLocal.get();
        // 本地线程这里获取的是拦截器在业务执行之前自动分配的临时用户，则在请求之后重新设置过期时间
        if (userInfoTo.getUserId() == null) {
            Cookie cookie = new Cookie(CartConstant.TEMP_USER_COOKIE_NAME, memberThreadLocal.get().getUserKey());
            cookie.setDomain("gulimall.com");
            cookie.setMaxAge(CartConstant.TEMP_USER_COOKIE_MAX_AGE);
            response.addCookie(cookie);
        }
    }
}
